#!/usr/bin/env python
# -*- coding: utf-8 -*-
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HEADER ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
SYNOPSIS

    wriite.py [-h,--help] [-v,--verbose]

DESCRIPTION

    Basic collective writer using twitter.

EXAMPLES

    # to launch this application :
    python wriite.py -v -u mysqlserver.org -l username -w password -d databaseName
    
AUTHOR

    Jerome Monceaux <bilock@gmail.com>

LICENSE

    Copyright (c) 2012, Jerome Monceaux
    All rights reserved.
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    
        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in the
          documentation and/or other materials provided with the distribution.
        * The name of contributors may not be used to endorse or promote products
          derived from this software without specific prior written permission.
    
    THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

VERSION

    $Id$
"""

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OPTIONS PARSING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TODO : optparse is deprecated. Use argparse instead...
import optparse
parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), usage=globals()['__doc__'], version='$Id$')
parser.add_option ('-v', '--verbose', action='store_true', default=False, help='verbose output')
parser.add_option ('-l', '--login', help='mysql login')
parser.add_option ('-w', '--password', help='mysql password')
parser.add_option ('-d', '--database', help='mysql database name')
parser.add_option ('-u', '--host', help='mysql host url')
parser.add_option ('-p', '--port', default=3306, help='mysql port')

(options, args) = parser.parse_args()

def Verbose(objToPrint=""):
  """Print a string if verbose is true"""
  global options
  try:
    if options.verbose: print "VERBOSE :", str(objToPrint)
  except:
    pass

Verbose( "wriite:"+ str( options ))



import sys
sys.path.append("/home/bilock/") # quick fix to find pymysql on the server.

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CORE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import twitter, pymysql, time
api = twitter.Api()

def _cleanMessage(text):
  """Remove @wriite and space character"""
  Verbose("Message : " + text)
  text = text.lower()
  text = text.replace("@wriite","")
  text = text.replace(" ","")
  text = text.replace("space"," ")
  return text

def _getLetter(text):
  """return the first letter. Only the first char is consider as the vote."""
  if( len(text) > 12):  # ignore long message
    return None
  if( "#ff" in text):   # ignore follow friday tags
    return None
  return text[0]

if __name__ == '__main__':
  
  # Connection to the mysql database
  conn = pymysql.connect(host=options.host, port=options.port, user=options.login, passwd=options.password, db=options.database)
  cur = conn.cursor()

  # get twitter access configuration
  Verbose("Read configuration from SQL database")
  if (cur.execute("SELECT * FROM  `wriite_config` ") is not 1) : 
    Verbose("Error occurs during sql request : SELECT * FROM  `wriite_config` ")
  r = cur.fetchall()[0]
  (accessTokenKey,accessTokenSecret,consumerKey,consumerSecret,threshold) = r
  Verbose("(accessTokenKey,accessTokenSecret,consumerKey,consumerSecret,threshold) = " + str(r))

  # get last votes to update the lastId. Tweets before the lastId are ignored
  if (cur.execute("SELECT * FROM  `wriite` ORDER BY id DESC LIMIT 1") is not 1) : 
    Verbose("Error occurs during sql request : SELECT * FROM  `wriite` ORDER BY id DESC LIMIT 1")
  (id,lastSentence,lastTweetId,lastThreshold,lastVotes) = cur.fetchall()[0]
  Verbose("lastId : " + str(lastTweetId))
  
  # read current values
  if (cur.execute("SELECT * FROM  `wriite_current` ") is not 1) : 
    Verbose("Error occurs during sql request : SELECT * FROM  `wriite_current` ")
  (date,currSentence,currVotes) = cur.fetchall()[0]
  date = float(date)
  Verbose("date : " + str(date))
  Verbose("currSentence : " + currSentence)
  Verbose("currVotes : " + currVotes)
  
  
  # connection to twitter
  api = twitter.Api(consumer_key        = consumerKey,
                    consumer_secret     = consumerSecret, 
                    access_token_key    = accessTokenKey, 
                    access_token_secret = accessTokenSecret
                   )
  
  ## Get followers lits
  #users = api.GetFollowers()
  #Verbose( "Number of followers :"+ str(len(users)))
  #Verbose( [s.screen_name for s in users] )
  
  # get all tweets mentioning @wriite since lastId 
  statuses = []
  p = 1
  while(True):
    r = api.GetMentions(since_id=lastTweetId ,page=p)
    Verbose("found " + str(len(r)) + " in page " + str(p))
    if(len(r) == 0):
      break
    statuses += r
    p += 1
    
  Verbose("Found " + str(len(statuses)) + " votes")
  Verbose( [[s.user.screen_name, s.text, s.id] for s in statuses])
  
  
  # Explore results
  backspace = 0
  votes = ''
  voters =[]
  statuses.reverse() # First vote of double voters is used.
  for s in statuses:
    if( s.user.screen_name in voters ): # ignore multiple votes 
      Verbose("Found a multiple vote : " + s.user.screen_name)
      continue
    voters += [s.user.screen_name]
    if( lastTweetId < s.id ): # store this id in case of success
      lastTweetId = s.id
    text = _cleanMessage(s.text)
    v = _getLetter(text)
    if( v is None):
      continue
    votes += v # store user's vote
  Verbose("Votes = " + votes)
  
  # Is a new letter elected ?
  for c in votes:
    if( votes.count(c) >= threshold): # YES, a new letter reach the threshold
      Verbose("Found " + str(votes.count(c)) + " " + c)
      currSentence += c
      req = 'INSERT INTO wriite (sentence,tweetId,threshold,votes) VALUES (\"' + \
          currSentence + '\",\"'+ \
          str(lastTweetId) + '\",' + str(threshold) + ',\"' + votes+'\")'
      Verbose("add req : " + req)
      if (cur.execute(req) is not 1) : 
        Verbose("Error occurs during sql insert request ")
        
      votes = '' # reset votes
      
      tweetSentence = "[bot] : " + currSentence + "_"
      Verbose(tweetSentence)
      try :
        status = api.PostUpdate(tweetSentence) # send a tweet with the new sentence.
      except : # Even if tweet failed we need to store current date in the mysql database
        pass
      break
  
  # store the current date to show that the bot is still active
  date = str(time.time())
  if (cur.execute('UPDATE wriite_current SET date=' + date + ', sentence="' + currSentence + '", votes="'+votes+'"') is not 1) : 
    Verbose("Error occurs during sql update request when udpating date")
  
  # close the sdl connection
  cur.close()
  conn.close()

